#include"CmdDeal.h"
#include"Polynomial.h"
#include"Window.h"
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cctype>
#include<stack>
using namespace std;

bool CmdDeal::AddPo(int mysize, double* M, string pname) {
    for (int i = 0; i < pname.size(); i++) {
        if (!((pname[i] >= 'A' && pname[i] <= 'Z') || (pname[i] >= 'a' && pname[i] <= 'z')))return false;
    }
    Polynomial P = Polynomial(mysize, M);
    P.AssignName(pname);
    Po.push_back(P);
    return true;
}

bool CmdDeal::ScanPo(string name) {
    for (int i = 0; i < Po.size(); i++) {
        if (name == Po[i].GetName()) {
            cout << name << "=" << Po[i] << endl;
            return true;
        }
    }
    return false;
}


int CmdDeal::findpo(string name) {
    for (int i = 0; i < this->Po.size(); i++) {
        if (name == this->Po[i].GetName())return i;
    }
    return -1;
}

int CmdDeal::analy(string ex) {
    tempn.clear();
    int index = 0;
    clean();
    while (index < ex.size()) {
        char c = ex[index];
        //如果遇到其他字符就把多项式名字推进去
        if (!isalpha(c)) {
            if (!tempn.empty()) {
                int i = findpo(tempn);
                if (i < 0)return -1;
                Polynomial pp = Po[i];
                stackpoly.push(Mypolynomial(pp, index-1));
            }
            tempn.clear();
        }
        if (isalpha(c)) {
            tempn += c;
        }
        //如果遇到定积分特殊处理
        if (c == '$') {
            de = 1;
            dot = 0;
            num = 0;
            if (cal_or_not(c)) {
                if (calculate() == -1)return -1;
                double a = 0, b = 0;
                dot = 0; num = 0;
                while (ex[index] != ']') {
                    index++;
                    if (ex[index] == '-')de = -1;
                    if (isdigit(ex[index])) {
                        if (dot == 0)num = num * 10.0 + ex[index]-'0';
                        if (dot != 0)num = num + (double)(ex[index]-'0') * pow(10, dot * (-1.0));
                    }
                    if (ex[index] == '.')dot++;
                    if (ex[index] == ',') { a = num * de; num = 0; dot = 0; de = 1; }
                }
                b = num;
                stackoper.push(Myoperator('$', a, b, index));
            }
            else {
                double a = 0, b = 0;
                dot = 0; num = 0;
                while (ex[index] != ']') {
                    index++;
                    if (ex[index] == '-')de = -1;
                    if (isdigit(ex[index])) {
                        if (dot == 0)num = num * 10.0 + ex[index]-'0';
                        if (dot != 0)num = num + (ex[index]-'0') * pow(10, dot * (-1.0));
                    }
                    if (ex[index] == '.')dot++;
                    if (ex[index] == ',') { a = num * de; num = 0; dot = 0; de = 1; }
                    if (!isdigit(ex[index])&&ex[index]!='['&&ex[index]!=']'&&ex[index]!='-'&&ex[index]!=','&& ex[index] != '.')return -1;
                }
                b = num;
                stackoper.push(Myoperator('$', a, b, index));
            }
        }
        if (c == '!') {
            if (cal_or_not(c)) {
                if (calculate() == -1)return -1;
                stackoper.push(Myoperator(c, index));
            }
            else stackoper.push(Myoperator(c, index));
        }

        if (c == ')') {
            while (stackoper.size() > 0 && stackoper.top().op != '(') {
                if (calculate() == -1) return -1;
            }
            stackoper.pop();
        }

        //左括号推进去，还有+和*也推进去
        if (c == '(')stackoper.push(Myoperator(c, index));
        if (c == '+' || c == '*') {
            if (cal_or_not(c)) {
                calculate();
                stackoper.push(Myoperator(c, index));
            }
            else {
                stackoper.push(Myoperator(c, index));
            }
        }
        index++;
    }
    if (!tempn.empty()) {
        int i = findpo(tempn);
        if (i < 0)return -1;
        Polynomial pp = Po[i];
        stackpoly.push(Mypolynomial(pp, index));
    }
    while (1) {
        if (stackpoly.size() == 1 && stackoper.size() == 0) { 
            return 0; 
        }
        if (stackpoly.size() == 0) { 
            clean();
            return -1; 
        }
        if (stackoper.size() == 0 && stackpoly.size() > 1) { 
            clean(); 
            return -1; 
        }
        if (calculate() == -1) { return -1; }
    }
}


int CmdDeal::calculate() {
    if (stackpoly.empty() || stackoper.empty())return -1;
    Myoperator myope = stackoper.top();
    stackoper.pop();
    if (myope.op == '(') {
        myope = stackoper.top();
        stackoper.pop();
    }
    Mypolynomial A = stackpoly.top();
    stackpoly.pop();
    switch (myope.op) {
    case '!': {
        if (myope.pos <= A.pos)return -1;
        stackpoly.push(Mypolynomial(A.Poly.coefficient(), A.pos));
        break;
    }
    case '$': {
        if (myope.pos >= A.pos)return -1;
        double a = myope.a;
        double b = myope.b;
        stackpoly.push(Mypolynomial(A.Poly.definite_integral(a, b), A.pos));
        break;
    }
    case '*': {
        if (stackpoly.empty())return -1;
        Mypolynomial B = stackpoly.top();
        stackpoly.pop();
        stackpoly.push(Mypolynomial(A.Poly * B.Poly, B.pos));
        break;
    }
    case '+': {
        if (stackpoly.empty())return -1;
        Mypolynomial B = stackpoly.top();
        stackpoly.pop();
        stackpoly.push(Mypolynomial(A.Poly + B.Poly, B.pos));
        break;
    }
    default:break;
    }
    return 0;
}




int CmdDeal::getPriority(char c) {
    if (c == '(') return 4;
    if (c == '!') return 4;
    if (c == '$') return 3;
    if (c == '*') return 2;
    if (c == '+') return 1;
}
int CmdDeal::getPrioritycal(char c) {
    if (c == '(') return -1;
    if (c == '!') return 4;
    if (c == '$') return 3;
    if (c == '*') return 2;
    if (c == '+') return 1;
}

int CmdDeal::cal_or_not(char c) {
    if (stackoper.empty())return 0;
    Myoperator t = stackoper.top();
    if (getPrioritycal(c) <= getPrioritycal(t.op))return 1;
    else return 0;
}